package com.easyfile.easyfilemaster.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.easyfile.easyfilemaster.entity.UserDetail;
import com.easyfile.easyfilemaster.entity.UserInfo;
import com.easyfile.easyfilemaster.entity.base.LoginResult;
import com.easyfile.easyfilemaster.entity.base.Result;
import com.easyfile.easyfilemaster.entity.base.ResultFactory;
import com.easyfile.easyfilemaster.entity.dto.*;
import com.easyfile.easyfilemaster.exception.user.*;
import com.easyfile.easyfilemaster.mapper.UserMapper;
import com.easyfile.easyfilemaster.service.FileService;
import com.easyfile.easyfilemaster.service.UserService;
import com.easyfile.easyfilemaster.utils.JwtUtil;
import com.easyfile.easyfilemaster.utils.Md5Util;
import com.easyfile.easyfilemaster.utils.SmsUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 用户业务
 * @author chenpeman
 * @date 2022年5月5日
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Resource
    private RedisTemplate<String,Object> redisTemplate;
    @Resource
    private UserMapper userMapper;

    @Resource
    private FileService fileService;
    @Override
    public LoginResult<UserInfo> login(LoginDto loginDto) {
        //获取用户信息
        UserDetail userDetail = userMapper.selectOne(new LambdaQueryWrapper<UserDetail>()
                        .eq(UserDetail::getMobile,loginDto.getMobile())
        );
        //用户不存在
        if (userDetail==null){
            throw new UserNotFoundException("找不到该用户");
        }
        //密码错误
        if (!Md5Util.checkPassword(loginDto.getPassword(),userDetail.getPassword(),userDetail.getSalt())) {
            throw new UserPasswordErrorException("用户名或密码错误");
        }
        //生成token
        UserInfo userInfo = userDetail.toUserInfo();
        String token = JwtUtil.createToken(userInfo);
        //返回结果
        return ResultFactory.success(userInfo,"登陆成功").toLoginResult(token);
    }

    @Override
    public LoginResult<UserInfo> mobileRegister(MobileRegisterDto mobileRegisterDto) {
        //判断该号码是否已注册
        Long id = userMapper.getIdByMobile(mobileRegisterDto.getMobile());
        if (id!=null){
            throw new UserHasRegisterException("用户已注册");
        }
        //判断验证码是否过期
        Object o = redisTemplate.opsForValue().get("verCode:" + mobileRegisterDto.getMobile());
        if (o==null){
            throw new VerCodeExpiredException("未发送验证码或验证码已失效");
        }
        //判断验证码是否一致
        String redisVerCode = (String) o;
        if (!redisVerCode.equals(mobileRegisterDto.getVerCode())){
            throw new VerCodeErrorException("验证码不一致");
        }
        //加密密码
        String salt = UUID.randomUUID()
                .toString()
                .replaceAll("-", "");
        String md5Password = Md5Util.getMd5Password(mobileRegisterDto.getPassword(), salt);
        //封装用户对象
        UserDetail userDetail = UserDetail.builder()
                .mobile(mobileRegisterDto.getMobile())
                .username(mobileRegisterDto.getUsername())
                .password(md5Password)
                .salt(salt)
                .maxCapacity(1073741824.0)
                .usedCapacity(0.0)
                .build();
        //用户对象入库
        int row = userMapper.insert(userDetail);
        if (row!=1){
            throw new InsertUserException("用户信息入库失败");
        }
        //签发token
        UserInfo userInfo = userDetail.toUserInfo();
        String token = JwtUtil.createToken(userInfo);
        if (token==null){
            throw new CreateTokenException("签发token失败");
        }
        //创建根目录文件夹
        fileService.createDefaultFolder(userInfo.getId());

        return ResultFactory.success(userInfo,"注册并登录成功").toLoginResult(token);
    }

    @Override
    public Result<Void> getVerCode(String mobile) {
        //发送短信验证码
        String verCode = SmsUtils.getSms(mobile);
        //String verifyCode = String.valueOf(new Random().nextInt(899999) + 100000);
        log.info("send verCode[{}]=>[{}]",verCode,mobile);
        if (verCode==null){
            throw new SendVerCodeException("发送验证码失败");
        }
        //保存验证码至Redis
        redisTemplate.opsForValue().set("verCode:"+mobile,verCode,5, TimeUnit.MINUTES);
        //redisTemplate.opsForValue().set("verCode:"+mobile,verifyCode,5, TimeUnit.MINUTES);
        return ResultFactory.success("发送成功");
    }

    @Override
    public LoginResult<UserInfo> checkToken(String token) {
        //校验token
        UserInfo userInfo = JwtUtil.checkToken(token);
        if (userInfo==null){
            throw new TokenCheckFailureException("登陆状态已过期");
        }
        //token续期
        UserDetail userDetail = userMapper.selectById(userInfo.getId());
        if (userDetail==null){
            throw new CreateTokenException("用户不存在");
        }
        UserInfo newUserInfo = userDetail.toUserInfo();
        String newToken = JwtUtil.createToken(newUserInfo);
        if (newToken==null){
            throw new CreateTokenException("签发token失败");
        }

        return ResultFactory.success(newUserInfo,"自动登陆成功").toLoginResult(newToken);
    }

    /**
     * 更新用户基本信息
     *
     * @param dto the user detail
     * @return the result
     */
    @Override
    public Result<Void> updateUser(UpdateUserDto dto) {
        UserDetail userDetail = userMapper.selectById(dto.getUserId());
        if (userDetail==null){
            throw new UpdateUserException("找不到[{"+dto.getUserId()+"}]用户");
        }
        userDetail.setUsername(dto.getUsername());
        userDetail.setSex(dto.getSex());
        userDetail.setMaxCapacity(dto.getMaxCapacity());
        int i = userMapper.updateById(userDetail);
        if (i!=1){
            throw new UpdateUserException("更新失败");
        }
        return ResultFactory.success("更新成功");
    }

    /**
     * 更新用户密码
     *
     * @param dto the dto
     * @return the result
     */
    @Override
    public Result<Void> updateUserPassword(UpdateUserPasswordDto dto) {
        //判断原始密码与新密码是否一致
        if (dto.getPreviousPassword().equals(dto.getNewPassword())){
            throw new UpdateUserPasswordException("原始密码与新密码不能相同");
        }
        UserDetail userDetail = userMapper.selectById(dto.getUserId());
        if (userDetail==null){
            throw new UpdateUserPasswordException("找不到[{"+dto.getUserId()+"}]用户");
        }
        //判断原始密码是否一致
        boolean b = Md5Util.checkPassword(dto.getPreviousPassword(), userDetail.getPassword(), userDetail.getSalt());
        if (!b){
            throw new UserPasswordErrorException("请输入正确的原始密码");
        }
        //更新密码
        String md5Password = Md5Util.getMd5Password(dto.getNewPassword(), userDetail.getSalt());
        userDetail.setPassword(md5Password);
        int i = userMapper.updateById(userDetail);
        if (i!=1){
            throw new UpdateUserPasswordException("更新失败");
        }

        return ResultFactory.success("更新成功");
    }

    /**
     * 更新用户手机号
     *
     * @param dto the dto
     * @return the result
     */
    @Override
    public Result<Void> updateUserMobile(UpdateUserMobileDto dto) {
        //判断该号码是否已注册
        Long id = userMapper.getIdByMobile(dto.getNewMobile());
        if (id!=null){
            throw new UserHasRegisterException("该号码已被注册");
        }
        //判断验证码是否过期
        Object o = redisTemplate.opsForValue().get("verCode:" + dto.getNewMobile());
        if (o==null){
            throw new VerCodeExpiredException("未发送验证码或验证码已失效");
        }
        //判断验证码是否一致
        String redisVerCode = (String) o;
        if (!StrUtil.equals(redisVerCode,dto.getVerCode())){
            throw new VerCodeErrorException("验证码不一致");
        }
        //更新用户信息
        UserDetail userDetail = userMapper.selectById(dto.getUserId());
        if (userDetail==null){
            throw new UserNotFoundException("该用户不存在");
        }
        userDetail.setMobile(dto.getNewMobile());
        int i = userMapper.updateById(userDetail);
        if (i!=1){
            throw new UpdateUserException("更新用户信息失败");
        }
        return ResultFactory.success("修改成功");
    }
}
